home *** CD-ROM | disk | FTP | other *** search
/ Technotools / Technotools (Chestnut CD-ROM)(1993).ISO / os2tools / os2life / life2.asm < prev    next >
Encoding:
Assembly Source File  |  1988-02-29  |  10.5 KB  |  388 lines

  1. ;***    life2.asm - assembler routines for life.c
  2. ;*
  3. ;*    Contains:    _draw_grid - draws 79x45 grid on screen
  4. ;*            _dostep    - advances the internal and screen grids
  5. ;*                     one generation
  6. ;*            scrfill    - private screen routine for _dostep
  7. ;*            scrremove  - private screen routine for _dostep
  8. ;*
  9. ;*  Created by Microsoft Corp. 1987
  10.  
  11.  
  12. ;***    segment definitions for the link with C
  13. ;
  14. _TEXT    SEGMENT  BYTE PUBLIC 'CODE'
  15. _TEXT    ENDS
  16. _DATA    SEGMENT  WORD PUBLIC 'DATA'
  17. _DATA    ENDS
  18. CONST    SEGMENT  WORD PUBLIC 'CONST'
  19. CONST    ENDS
  20. _BSS    SEGMENT  WORD PUBLIC 'BSS'
  21. _BSS    ENDS
  22. DGROUP    GROUP    CONST, _BSS, _DATA
  23.     ASSUME    CS: _TEXT, DS: DGROUP, SS: DGROUP, ES: DGROUP
  24.  
  25. ;***    the public routines
  26. ;
  27.     PUBLIC    _draw_grid, _dostep
  28.  
  29.  
  30. ;***    Global variables from LIFE.C
  31. ;
  32.     EXTRN    _ScrSeg:WORD
  33.     EXTRN    _ScrCol:WORD
  34.     EXTRN    _ScrRow:WORD
  35.  
  36. ;***    OS/2 functions
  37. ;
  38.     EXTRN    VIOSCRUNLOCK:FAR
  39.     EXTRN    VIOSCRLOCK:FAR
  40.  
  41.  
  42. _TEXT       SEGMENT
  43. ;***    _draw_grid - clears screen and draws 79x45 grid
  44. ;*
  45. ;*    Entry:    ds:_ScrSeg - screen buffer segment, from life.c
  46. ;*
  47. ;*    Exit:    None
  48. ;*
  49. _draw_grid    PROC NEAR
  50.     push    bp            ; startup
  51.     mov    bp,sp
  52.     sub    sp,2            ; one word variable for VIOSCRLOCK
  53.     push    di            ; save register used by C compiler
  54.  
  55. ;    get screen access
  56.     mov    ax,1
  57.     push    ax            ; wait until screen available
  58.     lea    ax,byte ptr [bp-2]
  59.     push    ss
  60.     push    ax            ; far address of return code
  61.     sub    ax,ax
  62.     push    ax            ; reserved word
  63.     call    VIOSCRLOCK        ; call DOS for access
  64.  
  65. ;    get parameter and set up
  66.     mov    es,ds:_ScrSeg        ; (es) = screen buffer segment
  67.     xor    di,di            ; (di) = offset in screen (start at 0)
  68.  
  69. ;    loop to draw 45 rows of the tops and middles of grid squares
  70.     mov    dx,45            ; (dx) = rows of grid squares, counter
  71. dg1:    mov    ax,5555h        ; (ax) = alternating bit pattern
  72.     mov    cx,39            ; (cx) = number of full words on a line
  73.     rep    stosw            ; fill line with 5555h
  74.     mov    es:[di],al        ; finish off last odd byte
  75.     inc    di            ; (di) = start of next row
  76.     inc    di
  77.     mov    ax,08080h        ; (ax) = left bit on
  78.     mov    cx,40            ; (cx) = number of words on a line
  79.     rep    stosw            ; fill next line with f0f0h
  80.     dec    dx            ; at screen bottom?
  81.     jnz    dg1            ; if no, loop
  82.  
  83. ;    draw the last line
  84.     mov    ax,5555h        ; (ax) = alternating bits
  85.     mov    cx,39            ; (cx) = full words on last line
  86.     rep    stosw            ; do fill
  87.     mov    es:[di],al        ; finish off line with odd byte
  88.  
  89. ;    clear bottom on screen on even bit plane
  90.     inc    di            ; (di) = start of last few lines
  91.     sub    ax,ax            ; (ax) = blank
  92.     mov    cx,400            ; (cx) = words left at bottom
  93.     rep    stosw
  94.  
  95. ;    draw the grid lines on the odd bit plane
  96.     mov    di,2000h        ; (di) = top of odd bit plane
  97.     mov    ax,08080h        ; (ax) = left bit on
  98.     mov    cx,40*2*45        ; (cx) = words to fill
  99.     rep    stosw            ; fill remainder with f0f0h
  100.  
  101. ;    clear bottom on screen on odd bit plane
  102.     sub    ax,ax            ; (ax) = blank
  103.     mov    cx,400            ; (cx) = words left at bottom
  104.     rep    stosw
  105.  
  106. ;    return the screen
  107.     sub    ax,ax
  108.     push    ax            ; reserved word
  109.     call    VIOSCRUNLOCK        ; call DOS to return screen
  110.  
  111. ;    return
  112.     pop    di
  113.     mov    sp,bp
  114.     pop    bp
  115.     ret
  116. _draw_grid    ENDP
  117.  
  118.  
  119. ;***    _dostep - advances InGrid one generation.
  120. ;*
  121. ;*    Entry:    char far *INGRID - InGrid, main internal bit map of cells
  122. ;*        char far *INGRID2 - InGrid2, working area of same size
  123. ;*        unsigned INROW - InRow, bits per row of above to areas
  124. ;*        unsigned INCOL - InCol, rows of above to areas
  125. ;*        ds:_ScrSeg     - from life.c
  126. ;*        ds:_ScrRow     - from life.c
  127. ;*        ds:_ScrCol     - from life.c
  128. ;*
  129. ;*    Exit:    InGrid is updated on generation in accordance with
  130. ;*        the rules of life.
  131. ;*        Returns in AX the return code from its VIOSCRLOCK call
  132. ;*
  133. INGRID EQU [bp+4]
  134. INGRID2 EQU [bp+8]
  135. INROW EQU [bp+12]
  136. INCOL EQU [bp+14]
  137.  
  138. _dostep PROC    NEAR
  139.     push    bp
  140.     mov    bp,sp
  141.     sub    sp,2            ; make room for local var
  142.     push    di
  143.     push    si
  144.     push    es
  145.     push    ds
  146.  
  147.     ; try to lock screen and put return code in [BP-2]
  148.     xor    ax,ax
  149.     push    ax            ; don't wait until screen available
  150.     lea    ax,byte ptr [bp-2]
  151.     push    ss
  152.     push    ax            ; far address of return code
  153.     sub    ax,ax
  154.     push    ax            ; reserved word
  155.     call    VIOSCRLOCK        ; call DOS for access
  156.  
  157.     ; get pointers to the two internal grids
  158.     les    di,INGRID2         ; (es:di) = @InGrid2
  159.     lds    si,INGRID        ; (ds:si) = @InGrid
  160.  
  161.     ; copy InGrid into InGrid2
  162.     mov    ax,INCOL          ; (ax) = cells per row
  163.     mul    word ptr INROW          ; (ax) = total cells
  164.     mov    cl,4
  165.     shr    ax,cl            ; (ax) = cell/16 = total words
  166.     mov    cx,ax            ; (cx) = total words
  167.     rep    movsw            ; move InGrid into InGrid2
  168.  
  169.  
  170.     ; main step loop
  171.     ;   I use a rather odd algorithm.  "neighbors" is defined
  172.     ;   here as all cells in a 3x3 grid summed.  If neighbors < 3, the
  173.     ;   the cell in the center is turned off.  If neighbors = 3, the cell
  174.     ;   is turned on.  If neighbors = 4, the cell is left in its current
  175.     ;   state.  If neighbors > 4, the cell is turned off.
  176.     push    ds
  177.     pop    es            ; (es) = InGrid's segment
  178.     lds    bx,INGRID2         ; (ds) = InGrid2's segment
  179.                     ; (bx) = pointer to offset in both
  180.     mov    di,INROW          ; (di) = row count
  181.     mov    si,INCOL          ; (si) = column count
  182.     shr    si,1
  183.     shr    si,1
  184.     shr    si,1            ; (si) = bytes per row in grids
  185.  
  186.     ; loop within the grid through all its rows
  187.     ;    here we come when at the start of a row
  188. ds1:    mov    cx,INCOL          ; (cx) = column count
  189.     mov    al,80h            ; (al) = bit mask for current bit
  190.     xor    dx,dx            ; (dh) = #of neighbors 1 col back
  191.                     ; (dl) = #of neighbors at cur col
  192.  
  193.     ; get number of neighbors on current row
  194. ds2:    xor    ah,ah            ; (ah) = count of neighbors on cur row
  195.     test    ds:[bx],al        ; is current bit on?
  196.     jz    ds3            ; if not go on
  197.     inc    ah            ; if yes, inc neighbor count
  198. ds3:    cmp    bx,si            ; are we on top row
  199.     jb    ds4            ; if yes, don't check above top
  200.     push    bx            ; save bx
  201.     sub    bx,si            ; backup bx to previous row
  202.     test    ds:[bx],al        ; is up a row bit on?
  203.     pop    bx            ; restore bx
  204.     jz    ds4            ; if not go on
  205.     inc    ah            ; if yes, inc neighbor count
  206. ds4:    cmp    di,1            ; are we on last row?
  207.     jz    ds5            ; if yes, don't read off edge
  208.     test    ds:[bx+si],al        ; is bit down a row on?
  209.     jz    ds5            ; if not, go on to final neighbor addin
  210.     inc    ah            ; if yes, inc neighbor count
  211.  
  212.     ; add up the total number of neighbors and decide what to do
  213. ds5:    cmp    cx,INCOL        ; are we at far left?
  214.     jz    ds12            ; if yes, don't affect bits off edge
  215.     add    dh,dl            ; (dh) = previous two rows of neighbors
  216.     add    dh,ah            ; (dh) = total neighbor count
  217.     cmp    dh,3
  218.     jb    ds6            ; if neighbors <3, turn off the cell
  219.     je    ds9            ; if neighbors = 3, turn on the cell
  220.     cmp    dh,4            ;
  221.     je    ds12            ; if neighbors = 4, do nothing
  222.  
  223.     ; turn off the center bit
  224. ds6:    rol    al,1            ; backup to center bit
  225.     jnc    ds7            ; if no overflow, go on
  226.     dec    bx            ; else, backup to last byte
  227. ds7:    test    es:[bx],al        ; is it already off
  228.     jz    ds8            ; if yes, don't do it again
  229.     not    al            ; turn on all bits but one to blank
  230.     and    es:[bx],al        ; force off bit in InGrid
  231.     not    al            ; restore al
  232.  
  233.     pop    ds            ; (ds) =  C's data ptr
  234.     call    scrremove        ; turn off on screen
  235.     push    ds            ; resave C's data ptr
  236.     mov    ds,[bp+8+2]        ; (ds) = seg of InGrid2
  237.  
  238. ds8:    ror    al,1            ; put back al to foreward bit
  239.     jnc    ds12            ; if no overflow, go to next bit
  240.     inc    bx            ; if overflow, restore bx
  241.     jmp    ds12            ; go on to next bitl
  242.  
  243.     ; turn on the center bit
  244. ds9:    rol    al,1            ; backup to center bit
  245.     jnc    ds10            ; if no overflow, go on
  246.     dec    bx            ; else, backup to last byte
  247. ds10:    test    es:[bx],al        ; is it already on?
  248.     jnz    ds11            ; if yes, don't do it again
  249.     or    es:[bx],al        ; force on bit in InGrid
  250.     pop    ds            ; (ds) =  C's data ptr
  251.     call    scrfill         ; turn on on screen
  252.     push    ds            ; resave C's data ptr
  253.     mov    ds,[bp+8+2]        ; (ds) = seg of InGrid2
  254. ds11:    ror    al,1            ; put back al to foreward bit
  255.     jnc    ds12            ; if no overflow, go to next bit
  256.     inc    bx            ; if overflow, restore bx
  257.  
  258.     ; advance to the next bit
  259. ds12:    ror    al,1            ; (al) mask advances to next bit
  260.     mov    dh,dl            ; move done neighbor count
  261.     mov    dl,ah            ; move the new neighbor row into bl
  262.     jnc    ds13            ; if still in same byte, jmp
  263.     inc    bx            ; if at byte end, advance to next byte
  264. ds13:    loop    ds2            ; loop through rest of bits on line
  265.  
  266.  
  267.     ; at the end of the row
  268.     dec    di            ; decrement row count
  269.     jz    dsx            ; if at end of grid, goto exit routine
  270.     jmp    ds1            ; if not at bottom, go to next row
  271.  
  272.     ; at the end of the grid
  273.     ; return the screen
  274. dsx:    cmp    byte ptr [bp-2],0    ; is the screen locked?
  275.     jnz    dsx1            ; if not, don't unlock
  276.  
  277.     sub    ax,ax
  278.     push    ax            ; reserved word
  279.     call    VIOSCRUNLOCK        ; call DOS to return screen
  280.  
  281. dsx1:    xor    ah,ah
  282.     mov    al,[bp-2]        ; return code from SCRLOCK
  283.  
  284.     pop    ds
  285.     pop    es
  286.     pop    si
  287.     pop    di
  288.     mov    sp,bp
  289.     pop    bp
  290.     ret
  291. _dostep ENDP
  292.  
  293.  
  294. ;***    scrfill - fills in a cell on the screen in 79x45 grid
  295. ;*
  296. ;*    Entry:    (di) = row number counted from bottom up (InRow-di=row to fill)
  297. ;*        (cx) = col number from right-1 (InCol-1-cx = col to fill)
  298. ;*        (ds) = data segment of life.c
  299. ;*
  300. ;*    Exit:    None, saves all registers
  301. ;*
  302. scrfill proc   near
  303.     cmp    [bp-2],byte ptr 0    ; is the screen available?
  304.     jnz    sfxx            ; if not, exit
  305.  
  306.     push    es
  307.     push    ax
  308.     push    bx
  309.     push    dx
  310.  
  311.     ; get screen pointer
  312.     mov    es,ds:_ScrSeg        ; (es) = screen buf segment
  313.     mov    ax,INROW
  314.     sub    ax,di            ; (ax) = row
  315.     cmp    ax,ds:_ScrRow        ; is it on the screen?
  316.     jae    sfx            ; if off, exit
  317.     mul    WORD PTR INCOL        ;     * InCol
  318.     shl    ax,1            ;     * 2
  319.     mov    dx,INCOL
  320.     sub    dx,cx
  321.     dec    dx            ;        (dx) = col to fill
  322.     cmp    dx,ds:_ScrCol        ; is it on the screen?
  323.     jae    sfx            ; if off, exit
  324.     add    ax,dx            ;     + col = scrn offset of cell
  325.  
  326.     ; fill in screen cell
  327.     mov    bx,ax            ; (es:bx) = far ptr to screen cell
  328.     mov    BYTE PTR es:[bx+2000h],7fh    ; first line of cell
  329.     mov    BYTE PTR es:[bx+80],7fh     ; second
  330.     mov    BYTE PTR es:[bx+2000h+80],7fh    ; third line of cell
  331.  
  332. sfx:    pop    dx
  333.     pop    bx
  334.     pop    ax
  335.     pop    es
  336. sfxx:    ret
  337. scrfill endp
  338.  
  339.  
  340. ;***    scrremove - removes a cell on the screen in 79x45 grid
  341. ;*
  342. ;*    Entry:    (di) = row number counted from bottom up (InRow-di=row to fill)
  343. ;*        (cx) = col number from right-1 (InCol-1-cx = col to fill)
  344. ;*        (ds) = data segment of life.c
  345. ;*
  346. ;*    Exit:    None, saves all registers
  347. ;*
  348. scrremove proc     near
  349.     cmp    [bp-2],byte ptr 0    ; is the screen available?
  350.     jnz    srxx            ; if not, exit
  351.  
  352.     push    es
  353.     push    ax
  354.     push    bx
  355.     push    dx
  356.  
  357.     ; get screen pointer
  358.     mov    es,ds:_ScrSeg        ; (es) = screen buf segment
  359.     mov    ax,INROW
  360.     sub    ax,di            ; (ax) = row
  361.     cmp    ax,ds:_ScrRow        ; is it on the screen?
  362.     jae    srx            ; if off, exit
  363.     mul    WORD PTR INCOL        ;     * InCol
  364.     shl    ax,1            ;     * 2
  365.     mov    dx,INCOL
  366.     sub    dx,cx
  367.     dec    dx            ;        (dx) = col
  368.     cmp    dx,ds:_ScrCol        ; is it on the screen?
  369.     jae    srx            ; if off, exit
  370.     add    ax,dx            ;     + col = scrn offset of cell
  371.  
  372.     ; remove screen cell
  373.     mov    bx,ax            ; (es:bx) = far ptr to screen cell
  374.     mov    BYTE PTR es:[bx+2000h],80h    ; first line of cell
  375.     mov    BYTE PTR es:[bx+80],80h     ; second
  376.     mov    BYTE PTR es:[bx+2000h+80],80h    ; third line of cell
  377.  
  378. srx:    pop    dx
  379.     pop    bx
  380.     pop    ax
  381.     pop    es
  382. srxx:    ret
  383. scrremove endp
  384.  
  385. _TEXT    ENDS
  386. END
  387. 
  388.